package drds.global_transaction.resource_manager.sql_recognizer.impl;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;

import drds.global_transaction.resource_manager.ParameterObjectList;
import drds.global_transaction.resource_manager.sql_recognizer.SqlParseException;
import drds.global_transaction.resource_manager.sql_recognizer.SqlType;

public class UpdateSqlRecognizer extends AbstractSqlRecognizer implements drds.global_transaction.resource_manager.sql_recognizer.UpdateSqlRecognizer
{

	private MySqlUpdateStatement mySqlUpdateStatement;

	public UpdateSqlRecognizer(String originalSql, SQLStatement mySqlUpdateStatement)
	{
		super(originalSql);
		this.mySqlUpdateStatement = (MySqlUpdateStatement) mySqlUpdateStatement;
	}

	@Override
	public SqlType getSqlType()
	{
		return SqlType.update;
	}

	@Override
	public String getTableSource()
	{
		StringBuilder sb = new StringBuilder();
		MySqlOutputVisitor mySqlOutputVisitor = new MySqlOutputVisitor(sb);
		SQLExprTableSource sqlExprTableSource = (SQLExprTableSource) mySqlUpdateStatement.getTableSource();
		mySqlOutputVisitor.visit(sqlExprTableSource);
		return sb.toString();
	}

	@Override
	public String getTableName()
	{
		StringBuilder sb = new StringBuilder();
		MySqlOutputVisitor mySqlOutputVisitor = new MySqlOutputVisitor(sb)
		{

			@Override
			public boolean visit(SQLExprTableSource sqlExprTableSource)
			{
				printTableSourceExpr(sqlExprTableSource.getExpr());
				return false;
			}
		};
		SQLExprTableSource sqlUpdateStatementTableSource = (SQLExprTableSource) mySqlUpdateStatement.getTableSource();
		mySqlOutputVisitor.visit(sqlUpdateStatementTableSource);
		return sb.toString();
	}

	//
	@Override
	public List<String> getUpdateColumnNameList()
	{
		List<SQLUpdateSetItem> sqlUpdateSetItemList = mySqlUpdateStatement.getItems();
		List<String> columnNameList = new ArrayList<>(sqlUpdateSetItemList.size());
		for (SQLUpdateSetItem sqlUpdateSetItem : sqlUpdateSetItemList)
		{
			SQLExpr sqlExpr = sqlUpdateSetItem.getColumn();
			if (sqlExpr instanceof SQLIdentifierExpr)
			{
				columnNameList.add(((SQLIdentifierExpr) sqlExpr).getName());
			} else if (sqlExpr instanceof SQLPropertyExpr)
			{
				// This is alias case, like UPDATE xxx_tbl a SET a.name = ? WHERE a.id = ?
				SQLExpr owner = ((SQLPropertyExpr) sqlExpr).getOwner();
				if (owner instanceof SQLIdentifierExpr)
				{
					columnNameList.add((((SQLIdentifierExpr) owner).getName() + "." + ((SQLPropertyExpr) sqlExpr).getName()));
				}
			} else
			{
				throw new SqlParseException("unknown SQLExpr: " + sqlExpr.getClass() + " " + sqlExpr);
			}
		}
		return columnNameList;
	}

	@Override
	public List<Object> getUpdateColumnValueList()
	{
		List<SQLUpdateSetItem> sqlUpdateSetItemList = mySqlUpdateStatement.getItems();
		List<Object> objectList = new ArrayList<>(sqlUpdateSetItemList.size());
		for (SQLUpdateSetItem updateSetItem : sqlUpdateSetItemList)
		{
			SQLExpr sqlExpr = updateSetItem.getValue();
			if (sqlExpr instanceof SQLValuableExpr)
			{
				objectList.add(((SQLValuableExpr) sqlExpr).getValue());
			} else if (sqlExpr instanceof SQLVariantRefExpr)
			{
				objectList.add(new VMarker());
			} else
			{
				throw new SqlParseException("unknown SQLExpr: " + sqlExpr.getClass() + " " + sqlExpr);
			}
		}
		return objectList;
	}

	@Override
	public String getWhereCondition(final ParameterObjectList parameterObjectList, final ArrayList<Object> paramAppender)
	{
		SQLExpr where = mySqlUpdateStatement.getWhere();
		if (where == null)
		{
			return "";
		}
		StringBuilder sb = new StringBuilder();
		MySqlOutputVisitor mySqlOutputVisitor = new MySqlOutputVisitor(sb)
		{
			@Override
			public boolean visit(SQLVariantRefExpr sqlVariantRefExpr)
			{
				if ("?".equals(sqlVariantRefExpr.getName()))
				{
					List<Object> objectList = parameterObjectList.getParameterObjectList()[sqlVariantRefExpr.getIndex()];
					paramAppender.add(objectList.get(0));
				}
				return super.visit(sqlVariantRefExpr);
			}
		};
		mySqlOutputVisitor.visit((SQLBinaryOpExpr) where);
		return sb.toString();
	}

	@Override
	public String getWhereCondition()
	{
		SQLExpr where = mySqlUpdateStatement.getWhere();
		if (where == null)
		{
			return "";
		}
		StringBuilder sb = new StringBuilder();
		MySqlOutputVisitor mySqlOutputVisitor = new MySqlOutputVisitor(sb);
		mySqlOutputVisitor.visit((SQLBinaryOpExpr) where);
		return sb.toString();
	}

}
